/**
 * Module:  module_uart
 * Version: 1v1
 * Build:   0ddac49116f3de7724075e8518932a0494c5460f
 * File:    uart.xc
 *
 * The copyrights, all other intellectual and industrial 
 * property rights are retained by XMOS and/or its licensors. 
 * Terms and conditions covering the use of this code can
 * be found in the Xmos End User License Agreement.
 *
 * Copyright XMOS Ltd 2010
 *
 * In the case where this code is a modification of existing code
 * under a separate license, the separate license terms are shown
 * below. The modifications to the code are still covered by the 
 * copyright notice above.
 *
 **/
#include <mox.h>
#include <mox_module.h>
#include <xs1.h>
#include <platform.h>
#include "module_uart.h"


inline void uart_module_start(streaming chanend mox, streaming chanend rxc1, streaming chanend rxc2, streaming chanend txc1, streaming chanend txc2, port rx, port tx)
{

	par {
		uart_tx(tx, txc1);
		uart_rx(rx, rxc1);
		mox_handler(mox, rxc2, txc2);
	}
}

inline void uart_tx(port TXD, streaming chanend txData_chan)
{
  unsigned byte, time;
  timer t;

  // Initial stop level
  TXD <: 1;

  while (1) {
    /* get next byte to transmit */
    txData_chan :> byte;
    t :> time ;

    /* output start bit */
    TXD <: 0;
    time += UART_BIT_TIME ;
    t when timerafter ( time ) :> void ;

    /* output data bits */
    for ( int i=0; i <8; i ++) {
      TXD <: >> byte ;
      time += UART_BIT_TIME ;
      t when timerafter ( time ) :> void ;
    }

    /* output stop bit */
    TXD <: 1;
    time += UART_BIT_TIME ;
    t when timerafter ( time ) :> void ;
  }
}

inline void uart_rx(port RXD, streaming chanend rxData_chan)
{
  unsigned byte, time;
  unsigned levelTest;
  timer t;

  while (1) {
    /* wait for negative edge of start bit */
    RXD when pinseq (1) :> void ;
    RXD when pinseq (0) :> void ;

    /* move time into centre of bit */
    t :> time ;
    time += UART_BIT_TIME /2;
    t when timerafter ( time ) :> void ;

    /* Ensure start bit wasn't a glitch */
    RXD :> levelTest;
    if (levelTest == 0) {

      /* input data bits */
      for ( int i=0; i <8; i ++) {
        time += UART_BIT_TIME ;
        t when timerafter ( time ) :> void ;
        RXD :> >> byte ;
      }

      /* input stop bit */
      time += UART_BIT_TIME ;
      t when timerafter ( time ) :> void ;
      RXD :> levelTest ;

      /* Send rx data if stop bit valid */
      if (levelTest == 1) {
        byte = byte >> 24;
        rxData_chan <: byte;
      }
    }
  }
}

#pragma stackfunction 10
inline signed chan_in_noblock(streaming chanend c)
{
	signed int tmp;
	select {
	case c :> tmp:
		return tmp;
	default:
		return -1;
	}
}
